// Texture OpenGL
// (c) jimon game studio

#include "CTexture_OpenGL.h"
#include "IRender.h"
#include "ILogManager.h"
#include "IVariables.h"
#include "jeThreads.h"

#ifdef JE_RENDER_OPENGL

#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3

#include <gl\glu.h>
#pragma comment(lib,"glu32.lib")

namespace je
{
	namespace video
	{
		inline GLenum ConvertTextureFormat(TextureFormat Format)
		{
			switch(Format)
			{
			case TF_RGBA8:
				return GL_RGBA8;
			case TF_RGBA32F:
				return GL_RGBA32F;
			case TF_DEPTH32:
				return GL_DEPTH_COMPONENT32;
			case TF_RG16F:
				return GL_RG16F;
			default:
				JELOG_E("Unsupported texture format")
				return 0;
			}
		}

		//! Constructor
		CTexture_OpenGL::CTexture_OpenGL(u8 Type,CRender_OpenGL_Extensions * extensions,const jeVector2di & Size,IImage * Image,TextureFormat Format,s32 Flags,s32 Samples,OpenGLWorkMode WorkMode)
			:Extensions(extensions),OriginalSize(Size),CurrentWorkMode(WorkMode),CurrentSamples(Samples)
		{
			Extensions->Grab();

			switch(Type)
			{
			case 0:
			case 1:
				{
					RenderBufferMode = false;
					Extensions->SetActiveTexture(GL_TEXTURE0);
					if(CurrentWorkMode < OWM_OPENGL3)
						Extensions->Enable(GL_TEXTURE_2D);

					Extensions->CreateTextures(1,&TextureID);

					if(Type == 0)
						TextureType = GL_TEXTURE_2D;
					else
						TextureType = GL_TEXTURE_2D_MULTISAMPLE;

					//GL_TEXTURE_RECTANGLE TODO

					Extensions->BindTexture(TextureType, TextureID);

					Extensions->TextureParameter(TextureType,GL_TEXTURE_WRAP_S,GL_REPEAT);
					Extensions->TextureParameter(TextureType,GL_TEXTURE_WRAP_T,GL_REPEAT);
					
					if(Flags & TCF_FILTERED)
					{
						Extensions->TextureParameter(TextureType,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
						if(Flags & TCF_MIPMAPED)
							Extensions->TextureParameter(TextureType,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
						else
							Extensions->TextureParameter(TextureType,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
					}
					else
					{
						Extensions->TextureParameter(TextureType,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
						if(Flags & TCF_MIPMAPED)
							Extensions->TextureParameter(TextureType,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST);
						else
							Extensions->TextureParameter(TextureType,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
					}

					GLenum TextureFormat = ConvertTextureFormat(Format);

					if((TextureFormat == GL_RGBA8) && core::GetVariables()->GetVariablec8("OpenGL_Support_S3TC"))
					{
						if(Flags & TCF_COMPRESS_DXT3)
							TextureFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
						else if(Flags & TCF_COMPRESS_DXT5)
							TextureFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
						else
							TextureFormat = GL_RGBA8;
					}

					GLenum MainFormat = GL_RGBA;
					GLenum PixelFormatType = GL_UNSIGNED_BYTE;

					switch(Format)
					{
					case TF_RGBA8:
						MainFormat = GL_RGBA;
						break;
					case TF_RGBA32F:
						MainFormat = GL_RGBA;
						break;
					case TF_DEPTH32:
						MainFormat = GL_DEPTH_COMPONENT;
						break;
					case TF_RG16F:
						MainFormat = GL_RG;
						break;
					default:
						break;
					}

					if(Type == 0)
					{
						if(Image)
						{
							Image->Lock();
							if(Flags & TCF_MIPMAPED)
							{
								#pragma JE_THREAD_CRITICAL (___CTexture_OpenGL_Build2dMipmaps)
								gluBuild2DMipmaps(TextureType,TextureFormat,OriginalSize.X,OriginalSize.Y,MainFormat,PixelFormatType,Image->GetPtr());
							}
							else
								Extensions->LoadTexture2D(TextureType,0,TextureFormat,OriginalSize.X,OriginalSize.Y,0,MainFormat,PixelFormatType,Image->GetPtr());
							Image->UnLock();
						}
						else
							Extensions->LoadTexture2D(TextureType,0,TextureFormat,OriginalSize.X,OriginalSize.Y,0,MainFormat,PixelFormatType,NULL);
					}
					else
					{
						Extensions->SetTextureMultisample(TextureType,Samples,TextureFormat,OriginalSize.X,OriginalSize.Y,true);
					}

					if(CurrentWorkMode != OWM_30)
						Extensions->BindTexture(TextureType,NULL);
					if(CurrentWorkMode < OWM_OPENGL3)
						Extensions->Disable(GL_TEXTURE_2D);

					break;
				}
			case 2:
				{
					RenderBufferMode = true;

					if(CurrentWorkMode != OWM_11)
					{
						Extensions->GenerateRenderbuffers(1,&TextureID);
						Extensions->BindRenderBuffer(GL_RENDERBUFFER,TextureID);

						if((CurrentSamples > 0) && (CurrentWorkMode >= OWM_OPENGL3))
							Extensions->SetRenderBufferStorageMultisample(GL_RENDERBUFFER,Samples,ConvertTextureFormat(Format),OriginalSize.X,OriginalSize.Y);
						else
							Extensions->SetRenderBufferStorage(GL_RENDERBUFFER,ConvertTextureFormat(Format),OriginalSize.X,OriginalSize.Y);

						Extensions->BindRenderBuffer(GL_RENDERBUFFER,0);
					}
					break;
				}
			}
		}

		//! Destructor
		CTexture_OpenGL::~CTexture_OpenGL()
		{
			if(RenderBufferMode)
			{
				if(CurrentWorkMode != OWM_11)
					Extensions->DeleteRenderbuffers(1,&TextureID);
			}
			else
			{
				Extensions->SetActiveTexture(GL_TEXTURE0);
				if(CurrentWorkMode < OWM_OPENGL3)
					Extensions->Enable(GL_TEXTURE_2D);
				Extensions->DeleteTextures(1,&TextureID);
				if(CurrentWorkMode < OWM_OPENGL3)
					Extensions->Disable(GL_TEXTURE_2D);
			}

			Extensions->Drop();
		}

		//! Get Size
		const jeVector2di & CTexture_OpenGL::GetSize()
		{
			return OriginalSize;
		}

		//! Copy To
		void CTexture_OpenGL::CopyTo(ITexture * Texture)
		{
			if(RenderBufferMode)
				return;

			// TODO
			JELOG_E("No Support")
		}

		//! Copy To
		void CTexture_OpenGL::CopyTo(IImage * Image)
		{
			if(RenderBufferMode)
				return;

			// TODO
			JELOG_E("No Support")
		}

		//! Copy From
		void CTexture_OpenGL::CopyFrom(IImage * Image)
		{
			if(RenderBufferMode)
				return;

			// TODO
			JELOG_E("No Support")
		}
	}
}

#endif
